﻿using System;
using System.Collections.Generic;
using RapidRepository.Context;
using RapidRepository.View;
namespace RapidRepository
{
    /// <summary>
    /// The repository containing all methods for requesting changes within the document database.
    /// </summary>
    /// <typeparam name="TEntity">The type of the entity.</typeparam>
    public class RapidRepository<TEntity> where TEntity : IRapidEntity
    {
        #region Add

        /// <summary>
        /// Adds the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public virtual TEntity Add(TEntity entity)
        {
            Contract.Requires("entity", entity != null);

            RapidContext.CurrentContext.AddOperationRequest(new OperationRequest(entity, typeof(TEntity), OperationRequestType.Add));
            return entity;
        } 

        #endregion

        #region Update

        /// <summary>
        /// Updates the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public virtual TEntity Update(TEntity entity)
        {
            Contract.Requires("entity", entity != null);
            Contract.Requires("entity.Id", entity.Id != Guid.Empty);

            RapidContext.CurrentContext.AddOperationRequest(new OperationRequest(entity, typeof(TEntity), OperationRequestType.Update));
            return entity;
        } 

        #endregion

        #region Delete

        /// <summary>
        /// Deletes an entity with the specified id.
        /// </summary>
        /// <param name="id">The id.</param>
        public virtual void Delete(Guid id)
        {
            Contract.Requires("id", id != Guid.Empty);

            RapidContext.CurrentContext.AddOperationRequest(new OperationRequest(id, typeof(TEntity), OperationRequestType.Delete));
        }

        /// <summary>
        /// Deletes the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public virtual void Delete(TEntity entity)
        {
            Contract.Requires("entity", entity != null);
            Contract.Requires("entity.Id", entity.Id != Guid.Empty);

            RapidContext.CurrentContext.AddOperationRequest(new OperationRequest(entity, typeof(TEntity), OperationRequestType.Delete));
        } 

        #endregion

        #region Exists

        /// <summary>
        /// Returns true if the entity exists.
        /// </summary>
        /// <param name="id">The entity id.</param>
        public virtual bool Exists(Guid id)
        {
            Contract.Requires("id", id != Guid.Empty);

            return RapidContext.CurrentContext.Exists<TEntity>(id);
        } 

        #endregion

        #region GetById
        
        /// <summary>
        /// Gets the by id.
        /// </summary>
        /// <param name="id">The id.</param>
        public virtual TEntity GetById(Guid id)
        {
            Contract.Requires("id", id != Guid.Empty);

            return RapidContext.CurrentContext.GetById<TEntity>(id);
        } 

        #endregion

        #region GetAll

        /// <summary>
        /// Gets all entities within the database of the specified type.
        /// </summary>
        public virtual IList<TEntity> GetAll()
        {
            return RapidContext.CurrentContext.GetAll<TEntity>();
        } 

        #endregion

        #region Query

        /// <summary>
        /// Queries this instance.
        /// </summary>
        /// <typeparam name="TView">The type of the view.</typeparam>
        public List<TView> Query<TView>()
            where TView : IRapidView
        {
            return RapidContext.CurrentContext.LoadView<TView>(typeof(TEntity), typeof(TView));
        }

        #endregion

        #region Views

        /// <summary>
        /// Adds the view.
        /// </summary>
        /// <typeparam name="TView">The type of the view.</typeparam>
        /// <param name="mapViewExpression">The map view expression.</param>
        public static IRapidViewData<TEntity, TView> AddView<TView>(Func<TEntity, TView> mapViewExpression)
            where TView : IRapidView
        {
            Contract.Requires("mapViewExpression", mapViewExpression != null);

            RapidViewData<TEntity, TView> view = new RapidViewData<TEntity, TView>(mapViewExpression);
            RapidContext.AddRapidView(view);
            return view;
        }

        /// <summary>
        /// Synchronises the view.
        /// </summary>
        /// <typeparam name="TView">The type of the view.</typeparam>
        public static void SynchroniseView<TView>()
            where TView : IRapidView
        {
            RapidContext.SynchroniseView<TEntity, TView>();
        }

        #endregion
    }
}
